package filter

import (
	"bytes"
	"strings"
	"unicode"
)

var (
	// Punctuation 字典长度及字符串索引位置均相同
	// 半角中英文标点符号
	puncCN     = "·" + `~！…【】〖〗『』「」{}；：‘’“”〞〝，。〈〉《》、？（）〔〕—+=|`
	puncEN     = "`" + `~!…[][][][]{};:''"""",.<><>.?()()-+=|`
	puncCnRune = []rune(puncCN)
	puncEnRune = []rune(puncEN)
	// 全角中英文标点符号
	dbcPuncCN     = "·" + `～！…【】〖〗『』「」｛｝；：‘’“”〞〝，。＜＞《》、？（）〔〕－＋＝｜`
	dbcPuncEN     = "｀" + `～！…［］［］［］［］｛｝；：＇＇＂＂＂＂，．＜＞＜＞．？（）（）－＋＝｜`
	dbcPuncCnRune = []rune(dbcPuncCN)
	dbcPuncEnRune = []rune(dbcPuncEN)
)

// StripAllPunc 过滤掉任意中文及英文标点符号
func StripAllPunc(s string) string {
	s = strings.TrimSpace(s)
	if len(s) < 1 {
		return ""
	}
	var b bytes.Buffer
	b.Grow(len(s))
	for _, v := range s {
		if !unicode.IsPunct(v) {
			b.WriteRune(v)
		}
	}
	return b.String()
}

// ReplaceAllPunc 将任意中文及英文标点符号替换为指定字符
func ReplaceAllPunc(s string, repalce string) string {
	s = strings.TrimSpace(s)
	if len(s) < 1 {
		return ""
	}
	var b bytes.Buffer
	b.Grow(len(s))
	for _, v := range s {
		if !unicode.IsPunct(v) {
			b.WriteRune(v)
		} else if repalce != "" {
			b.WriteString(repalce)
		}
	}
	return strings.TrimSpace(b.String())
}

// ReplacePuncCN2EN 将中文标点符号替换为英文
//   - allowedDBC 是否允许全角标点符号，false => 不允许时全角将替换为半角
func ReplacePuncCN2EN(s string, allowedDBC bool) string {
	s = strings.TrimSpace(s)
	if len(s) < 1 {
		return ""
	}
	var b bytes.Buffer
	b.Grow(len(s))
	for _, v := range s {
		i := _stringRuneIndex(puncCN, v)
		j := _stringRuneIndex(dbcPuncCN, v)
		// 非中文标点符号
		if i < 0 && j < 0 {
			b.WriteRune(v)
			continue
		}
		// 半角标点符号
		if i >= 0 && j < 0 {
			b.WriteRune(puncEnRune[i])
			continue
		}
		// 全角/半角不区分的标点符号
		if i >= 0 && j >= 0 && puncCnRune[i] == dbcPuncCnRune[j] {
			b.WriteRune(puncEnRune[i])
			continue
		}
		if j >= 0 {
			if allowedDBC {
				//允许时将中文全角为英文全角
				b.WriteRune(dbcPuncEnRune[j])
			} else {
				//不允许时将中文全角为英文半角
				b.WriteRune(puncEnRune[j])
			}
		} else if i >= 0 {
			b.WriteRune(puncEnRune[i])
		}
	}
	return b.String()
}

// ReplacePuncEN2CN将英文标点符号替换为中文标点符号
//   - allowedDBC 是否允许全角标点符号，false => 不允许时全角将替换为半角
func ReplacePuncEN2CN(s string, allowedDBC bool) string {
	s = strings.TrimSpace(s)
	if len(s) < 1 {
		return ""
	}
	var (
		b       bytes.Buffer
		enLast  rune = 0
		dbcLast rune = 0
	)
	b.Grow(len(s))
	for _, v := range s {
		if i := _stringRuneIndex(puncEN, v); i >= 0 {
			index := i
			//中文标点特殊处理，英文'"不区分前后
			if v == '\'' || v == '"' {
				if enLast > 0 {
					enLast = 0
					index = i + 1
				} else {
					enLast = v
				}
			} else if v == '.' {
				if enLast > 0 {
					enLast = 0
					index = i + 3
				} else {
					enLast = v
				}
			}
			//替换为中文标点
			b.WriteRune(puncCnRune[index])
		} else if i := _stringRuneIndex(dbcPuncEN, v); i >= 0 {
			index := i
			//中文标点特殊处理，英文＇＂．不区分前后
			if v == '＇' || v == '＂' {
				if dbcLast > 0 {
					dbcLast = 0
					index = i + 1
				} else {
					dbcLast = v
				}
			} else if v == '．' {
				if dbcLast > 0 {
					dbcLast = 0
					index = i + 3
				} else {
					dbcLast = v
				}
			}
			if allowedDBC {
				//不允许时将英文全角为中文全角
				b.WriteRune(dbcPuncCnRune[index])
			} else {
				//不允许时将英文全角为中文半角
				b.WriteRune(puncCnRune[index])
			}
		} else {
			b.WriteRune(v)
		}
	}
	return b.String()
}

// 以Rune（UTF8字符）分割字符串，并找到目标字符的最左侧索引位置
func _stringRuneIndex(s string, target rune) int {
	if len(s) == 0 {
		return -1
	}
	i := 0
	for _, v := range s {
		if v == target {
			return i
		}
		i++
	}
	return -1
}
